/* 断言器,用于判断和抛出异常
 * 感谢 @冰麟轻武 提供的断言器工具类
 * 源地址：https://code.csdn.net/snippets/389206
 */

/*待测试*/
namespace LSLib.Tools
{
    using System;
    using System.Collections;
    using System.Collections.Generic;

    public static class Assertor
    {
        /// <summary> 如果value值是null 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void IsNull(object value, string paramName)
        {
            if (value == null)
            {
                throw new ArgumentNullException(paramName, "参数不能为null");
            }
        }

        #region IsNullOrEmpty——4重载
        /// <summary> 如果value字符串是null或string.Empty 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void IsNullOrEmpty(string value, string paramName)
        {
            if (value == null || value.Length == 0)
            {
                throw new ArgumentNullException(paramName, "字符串不能为null或空");
            }
        }

        /// <summary> 如果value集合是null或者Count是0 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void IsNullOrEmpty(ICollection value, string paramName)
        {
            if (value == null || value.Count == 0)
            {
                throw new ArgumentNullException(paramName, "集合不能为null且必须有元素");
            }
        }

        /// <summary> 如果value集合是null或者Count是0 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void IsNullOrEmpty<T>(T[] value, string paramName)
        {
            if (value == null || value.Length == 0)
            {
                throw new ArgumentNullException(paramName, "集合不能为null且必须有元素");
            }
        }

        /// <summary> 如果value集合是null或者Count是0 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void IsNullOrEmpty<T>(ICollection<T> value, string paramName)
        {
            if (value == null || value.Count == 0)
            {
                throw new ArgumentNullException(paramName, "集合不能为null且必须有元素");
            }
        }
        #endregion

        /// <summary> 如果value字符串是 null、空还是仅由空白字符组成 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void IsNullOrWhiteSpace(string value, string paramName)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentNullException(paramName, "字符串不能为null或连续的空白");
            }
        }

        #region AreInRange——3重载
        /// <summary> 如果value值超过min~max 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public static void AreInRange<T>(Nullable<T> value, string paramName, T min, T max)
            where T : struct, IComparable
        {
            if (value.HasValue)
            {
                if (value.Value.CompareTo(min) < 0 || value.Value.CompareTo(max) > 0)
                {
                    string msg = string.Format("值不能超出这个范围：{0}~{1}", min, max);
                    throw new ArgumentOutOfRangeException(paramName, value, msg);
                }
            }
        }

        /// <summary> 如果value值超过min~max 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public static void AreInRange<T>(T value, string paramName, T min, T max)
            where T : IComparable<T>
        {
            if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
            {
                string msg = string.Format("值不能超出这个范围：{0}~{1}", min, max);
                throw new ArgumentOutOfRangeException(paramName, value, msg);
            }
        }

        /// <summary> 如果value值超过min~max 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public static void AreInRange<T>(IComparable value, string paramName, T min, T max)
            where T : IComparable
        {
            if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
            {
                string msg = string.Format("值不能超出这个范围：{0}~{1}", min, max);
                throw new ArgumentOutOfRangeException(paramName, value, msg);
            }
        }
        #endregion

        #region AreType——2重载
        /// <summary> 如果value不是T类型或其子类 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void AreType<T>(object value, string paramName)
        {
            if ((value is T) == false)
            {
                string msg = string.Format("{0} 值不是指定的类型: '{1}'", value, typeof(T));
                throw new ArgumentOutOfRangeException("paramName", paramName, msg);
            }
        }

        /// <summary> 如果value不是Type类型或其子类 则抛出异常
        /// </summary>
        /// <param name="type">限定类型</param>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void AreType(Type type, object value, string paramName)
        {
            if (type.IsInstanceOfType(value) == false)
            {
                string msg = string.Format("{0} 值不是指定的类型: '{1}'", value, type);
                throw new ArgumentOutOfRangeException("paramName", paramName, msg);
            }
        }
        #endregion

        /// <summary> 如果value不是数字类型 则抛出异常
        /// </summary>
        /// <param name="value">参数值</param>
        /// <param name="paramName">参数名称</param>
        public static void IsNumberType(object value, string paramName)
        {
            var conv = value as IConvertible;
            if (conv == null)
            {
                var code = (int)conv.GetTypeCode();
                if (code < 5 || code > 15)
                {
                    throw new ArgumentOutOfRangeException("paramName", paramName, value + "不是数值类型");
                }
            }
        }

        #region IsTrue——2重载
        /// <summary> 如果condition是true 则抛出异常
        /// </summary>
        /// <param name="condition">判断条件</param>
        /// <param name="message">异常消息</param>
        public static void IsTrue<T>(bool condition, string message)
            where T : Exception, new()
        {
            if (condition)
            {
                var ex = new T();
                typeof(Exception).GetField("_message", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(ex, message);
                throw ex;
            }
        }

        /// <summary> 如果condition是true 则抛出NotSupportedException异常
        /// </summary>
        /// <param name="condition">判断条件</param>
        /// <param name="message">异常消息</param>
        public static void IsTrue(bool condition, string message)
        {
            IsTrue<NotSupportedException>(condition, message);
        }
        #endregion

        #region IsFalse——2重载
        /// <summary> 如果condition是false 则抛出异常
        /// </summary>
        /// <param name="condition">判断条件</param>
        /// <param name="message">异常消息</param>
        public static void IsFalse<T>(bool condition, string message)
            where T : Exception, new()
        {
            IsTrue<T>(!condition, message);
        }

        /// <summary> 如果condition是false 则抛出NotSupportedException异常
        /// </summary>
        /// <param name="condition">判断条件</param>
        /// <param name="message">异常消息</param>
        public static void IsFalse(bool condition, string message)
        {
            IsTrue<NotSupportedException>(!condition, message);
        }
        #endregion
    }
}
